//    entity language compiler Copyright (C) 2011 Vincent Belliard

//    This program is free software: you can redistribute it and/or modify
//    it under the terms of the GNU General Public License as published by
//    the Free Software Foundation version 3 of the License.

//    This program is distributed in the hope that it will be useful,
//    but WITHOUT ANY WARRANTY; without even the implied warranty of
//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//    GNU General Public License for more details.

//    You should have received a copy of the GNU General Public License
//    along with this program.  If not, see <http://www.gnu.org/licenses/>.

#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <typeinfo>
#include <sys/types.h>
#include <sys/stat.h>
#include "types.h"
#include "entity.h"
#include "method.h"
#include "type.h"
#include "expression.h"
#include "object_class.h"
#include "global.h"
#include "builtins.h"

// }{--------------------------------------------------------------

T_entity_compiler::T_entity_compiler(void)
{
errors_count = 0 ;
}

T_entity_compiler::~T_entity_compiler()
{
}

void T_entity_compiler::add_file(const T_string new_file_name)
{
T_entity_file *file = files.first ;
while (file != NULL)
	 {
	if (strcmp(file->file_name.string(), new_file_name.string()) == 0) return ;
	file = file->next ;
	}
files.insert(new T_entity_file(new_file_name)) ;
}

void T_entity_compiler::add_error(const char *format, ...)
{
va_list ap ;
va_start(ap, format) ;
vfprintf(stderr, format, ap) ;
fprintf(stderr, "\n") ;
va_end(ap) ;
errors_count++ ;
}

void T_entity_compiler::add_error(T_entity_location &where, const char *format, ...)
{
T_string_reference loc(where.location) ;
loc.restart() ;
T_string_reference line_start(loc) ;
int line = 1 ;
int column = 1 ;
for(;;)
	{
	if (loc == where.location) break ;
	unsigned last = loc.current() ;
	loc.increment() ;
	if (last == '\n')
		{
		line_start.set(loc) ;
		line++ ;
		column = 1 ;
		}
	else if (last == '\t')
		{
		column = (column / 4) * 4 + 5 ;
		}
	else
		{
		column++ ;
		}
	}
va_list ap ;
va_start(ap, format) ;
fprintf(stderr, "%s:%u:%u: ", where.file_name.string(), line, column) ;
vfprintf(stderr, format, ap) ;
fprintf(stderr, "\n") ;
va_end(ap) ;
errors_count++ ;

}

void T_entity_compiler::add_error(T_string_reference &where, const char *format, ...)
{
T_string_reference loc(where) ;
loc.restart() ;
T_string_reference line_start(loc) ;
int line = 1 ;
int column = 1 ;
for(;;)
	{
	if (loc == where) break ;
	unsigned last = loc.current() ;
	loc.increment() ;
	if (last == '\n')
		{
		line_start.set(loc) ;
		line++ ;
		column = 1 ;
		}
	else if (last == '\t')
		{
		column = (column / 4) * 4 + 5 ;
		}
	else
		{
		column++ ;
		}
	}
va_list ap ;
va_start(ap, format) ;
fprintf(stderr, "%s:%u:%u: ", file_name.string(), line, column) ;
vfprintf(stderr, format, ap) ;
fprintf(stderr, "\n") ;
va_end(ap) ;
}

int T_entity_compiler::is_identifier_character(unsigned loc, int first)
{
if (((loc >= 'a') && (loc <= 'z')) || ((loc >= 'A') && (loc <= 'Z')) || (loc == '_')) return TRUE ;
if (first) return FALSE ;
if ((loc >= '0') && (loc <= '9')) return TRUE ;
return FALSE ;
}

void T_entity_compiler::reduce_identifier(void)
{
T_string_reference start(current) ;
while (is_identifier_character(current.current(), FALSE)) current.increment() ;
current_item = entity_compiler_item_identifier ;
string.set(start, current) ;
}

void T_entity_compiler::reduce_full_identifier(void)
{
current.increment() ;
T_string_reference start(current) ;
for(;;)
	{
	unsigned loc = current.current() ;
	if (loc == 0)
		{
		add_error("unterminated identifier\n") ;
		current_item = entity_compiler_item_eof ;
		}
	if (loc == '`') break ;
	current.increment() ;
	}
current_item = entity_compiler_item_identifier ;
string.set(start, current) ;
current.increment() ;
}

void T_entity_compiler::reduce_integer(void)
{
unsigned long long loc = 0 ;
T_string_reference start(current) ;
if (current.current() == '0')
	{
	current.increment() ;
	if (current.current() == 'x')
		{
		current.increment() ;
		for(;;)
			{
			if (is_integer_character(current.current())) loc = loc * 16 + (current.current() - '0') ;
			else if (is_hexa_character(current.current())) loc = loc * 16 + (current.current() - 'A' + 10) ;
			else break ;
			current.increment() ;
			}
		}
	}
while (is_integer_character(current.current()))
	{
	loc = loc * 10 + (current.current() - '0') ;
	current.increment() ;
	}
current_item = entity_compiler_item_integer ;
integer = loc ;
}

void T_entity_compiler::reduce_character(void)
{
current.increment() ;
current_item = entity_compiler_item_character ;
unsigned loc = current.current() ;
if (loc == '\\')
	{
	current.increment() ;
	loc = current.current() ;
	if (((loc >= '0') && (loc <= '9')) || ((loc >= 'A') && (loc <= 'F')))
		{
		character = 0 ;
		for(;;)
			{
			loc = current.current() ;
			if ((loc >= '0') && (loc <= '9')) character = character * 16 + loc - '0' ;
			else if ((loc >= 'A') && (loc <= 'F')) character = character * 16 + loc - 'A' + 10 ;
			else break ;
			current.increment() ;
			}
		if (current.current() == ';') current.increment() ;
		}
	else if (loc == '\\')
		{
		character = '\\' ;
		current.increment() ;
		}
	else if (loc == 'n')
		{
		character = '\n' ;
		current.increment() ;
		}
	else if (loc == 'r')
		{
		character = '\r' ;
		current.increment() ;
		}
	else if (loc == 't')
		{
		character = '\t' ;
		current.increment() ;
		}
	else if (loc == 's')
		{
		character = ' ' ;
		current.increment() ;
		}
	else if (loc == 'f')
		{
		character = '\f' ;
		current.increment() ;
		}
	else if (loc == 'b')
		{
		character = '\b' ;
		current.increment() ;
		}
	else if (loc == '\"')
		{
		character = '\"' ;
		current.increment() ;
		}
	}
else
	{
	character = loc ;
	current.increment() ;
	}
}

void T_entity_compiler::reduce_string(void)
{
current.increment() ;
T_string_reference start(current) ;
for(;;)
	{
	unsigned loc = current.current() ;
	if (loc == 0)
		{
		add_error("unterminated string\n") ;
		current_item = entity_compiler_item_eof ;
		}
	if (loc == '\\')
		{
		current.increment() ;
		if (loc == 0)
			{
			add_error("unterminated string\n") ;
			current_item = entity_compiler_item_eof ;
			}
		}
	else
		{
		if (loc == '"') break ;
		}
	current.increment() ;
	}
/*
unsigned buffer_size = current.offset - start.offset ;
char *buffer = new char[buffer_size + 1] ;
char *dst = buffer ;
for(;;)
	{
	unsigned loc = start.current() ;
	if (loc == '\\')
		{
		current.increment() ;
		*dst++ = (char)start.current() ;
		}
	else
		{
		if (loc == '"') break ;
		*dst++ = (char)start.current() ;
		}
	start.increment() ;
	}
string.set(buffer, buffer_size) ;
*/
string.set(start, current) ;
current_item = entity_compiler_item_string ;
current.increment() ;
}

void T_entity_compiler::next_item(void)
{
for(;;)
	{
	unsigned loc = current.current() ;
	for(;;)
		{
		while ((loc == ' ') || (loc == '\n') || (loc == '\r') || (loc == '\t'))
			{
			current.increment() ;
			loc = current.current() ;
			}
		if (loc != '/') break ;
		T_string_reference next(current) ;
		next.increment() ;
		if (next.current() == '/')
			{
			current.increment() ;
			loc = current.current() ;
			for(;;)
				{
				current.increment() ;
				loc = current.current() ;
				if (loc == 0) break ;
				if ((loc == '\n') || (loc == '\r'))
					{
					current.increment() ;
					loc = current.current() ;
					break ;
					}
				}
			}
		else
			{
			break ;
			}
		}
	location.set(current) ;
	switch (loc)
		{
		case 0:
			current_item = entity_compiler_item_eof ;
			return ;
		case '{':
			current_item = entity_compiler_item_left_brace ;
			current.increment() ;
			return ;
		case '}':
			current_item = entity_compiler_item_right_brace ;
			current.increment() ;
			return ;
		case '[':
			current.increment() ;
			if (current.current() == '[')
				{
				current.increment() ;
				current_item = entity_compiler_item_left_left_bracket ;
				}
			else
				{
				current_item = entity_compiler_item_left_bracket ;
				}
			return ;
		case ']':
			current.increment() ;
			if (current.current() == ']')
				{
				current.increment() ;
				current_item = entity_compiler_item_right_right_bracket ;
				}
			else
				{
				current_item = entity_compiler_item_right_bracket ;
				}
			return ;
		case '(':
			current_item = entity_compiler_item_left_parenthesis ;
			current.increment() ;
			return ;
		case ')':
			current_item = entity_compiler_item_right_parenthesis ;
			current.increment() ;
			return ;
		case ';':
			current_item = entity_compiler_item_semicolon ;
			current.increment() ;
			return ;
		case ':':
			current_item = entity_compiler_item_colon ;
			current.increment() ;
			return ;
		case '=':
			current.increment() ;
			if (current.current() == '=')
				{
				current.increment() ;
				current_item = entity_compiler_item_equal_equal ;
				}
			else
				{
				current_item = entity_compiler_item_equal ;
				}
			return ;
		case '+':
			current.increment() ;
			if (current.current() == '+')
				{
				current.increment() ;
				current_item = entity_compiler_item_add_add ;
				}
			else if (current.current() == '=')
				{
				current.increment() ;
				current_item = entity_compiler_item_add_equal ;
				}
			else
				{
				current_item = entity_compiler_item_add ;
				}
			return ;
		case '-':
			current.increment() ;
			if (current.current() == '-')
				{
				current.increment() ;
				current_item = entity_compiler_item_minus_minus ;
				}
			else if (current.current() == '=')
				{
				current.increment() ;
				current_item = entity_compiler_item_minus_equal ;
				}
			else if (current.current() == '>')
				{
				current.increment() ;
				current_item = entity_compiler_item_minus_greater ;
				}
			else
				{
				current_item = entity_compiler_item_minus ;
				}
			return ;
		case '*':
			current.increment() ;
			if (current.current() == '=')
				{
				current.increment() ;
				current_item = entity_compiler_item_star_equal ;
				}
			else
				{
				current_item = entity_compiler_item_star ;
				}
			return ;
		case '/':
			current.increment() ;
			if (current.current() == '=')
				{
				current.increment() ;
				current_item = entity_compiler_item_slash_equal ;
				}
			else
				{
				current_item = entity_compiler_item_slash ;
				}
			return ;
		case '%':
			current.increment() ;
			if (current.current() == '=')
				{
				current.increment() ;
				current_item = entity_compiler_item_percent_equal ;
				}
			else
				{
				current_item = entity_compiler_item_percent ;
				}
			return ;
		case '&':
			current.increment() ;
			if (current.current() == '=')
				{
				current.increment() ;
				current_item = entity_compiler_item_ampersand_equal ;
				}
			else
				{
				current_item = entity_compiler_item_ampersand ;
				}
			return ;
		case '^':
			current.increment() ;
			if (current.current() == '=')
				{
				current.increment() ;
				current_item = entity_compiler_item_circumflex_equal ;
				}
			else
				{
				current_item = entity_compiler_item_circumflex ;
				}
			return ;
		case '$':
			current_item = entity_compiler_item_pipe_pipe ;
			current.increment() ;
			return ;
		case '|':
			current.increment() ;
			if (current.current() == '|')
				{
				current.increment() ;
				if (current.current() == '=')
					{
					current.increment() ;
					current_item = entity_compiler_item_pipe_pipe_equal ;
					}
				else
					{
					current_item = entity_compiler_item_pipe_pipe ;
					}
				}
			else
				{
				if (current.current() == '=')
					{
					current.increment() ;
					current_item = entity_compiler_item_pipe_equal ;
					}
				else
					{
					current_item = entity_compiler_item_pipe ;
					}
				}
			return ;
		case '<':
			current.increment() ;
			if (current.current() == '<')
				{
				current.increment() ;
				if (current.current() == '=')
					{
					current.increment() ;
					current_item = entity_compiler_item_less_less_equal ;
					}
				else
					{
					current_item = entity_compiler_item_less_less ;
					}
				}
			else
				{
				if (current.current() == '=')
					{
					current.increment() ;
					current_item = entity_compiler_item_less_equal ;
					}
				else
					{
					current_item = entity_compiler_item_less ;
					}
				}
			return ;
		case '>':
			current.increment() ;
			if (current.current() == '>')
				{
				current.increment() ;
				if (current.current() == '=')
					{
					current.increment() ;
					current_item = entity_compiler_item_greater_greater_equal ;
					}
				else
					{
					current_item = entity_compiler_item_greater_greater ;
					}
				}
			else
				{
				if (current.current() == '=')
					{
					current.increment() ;
					current_item = entity_compiler_item_greater_equal ;
					}
				else
					{
					current_item = entity_compiler_item_greater ;
					}
				}
			return ;
		case '!':
			current.increment() ;
			if (current.current() == '=')
				{
				current.increment() ;
				current_item = entity_compiler_item_exclamation_mark_equal ;
				}
			else
				{
				current_item = entity_compiler_item_exclamation_mark ;
				}
			return ;
		case ',':
			current_item = entity_compiler_item_comma ;
			current.increment() ;
			return ;
		case '.':
			current.increment() ;
			if (current.current() == '.')
				{
				current.increment() ;
				if (current.current() == '.')
					{
					current.increment() ;
					current_item = entity_compiler_item_dot_dot_dot ;
					}
				else
					{
					current_item = entity_compiler_item_dot_dot ;
					}
				}
			else
				{
				current_item = entity_compiler_item_dot ;
				}
			return ;
		case '?':
			current_item = entity_compiler_item_question_mark ;
			current.increment() ;
			return ;
		case '~':
			current_item = entity_compiler_item_tilde ;
			current.increment() ;
			return ;
		case '"':
			reduce_string() ;
			return ;
		case '#':
			reduce_character() ;
			return ;
		case '`':
			reduce_full_identifier() ;
			return ;
		default:
			if (is_identifier_character(loc, TRUE))
				{
				reduce_identifier() ;
				return ;
				}
			if (is_integer_character(loc))
				{
				reduce_integer() ;
				return ;
				}
			break ;
		}
	add_error(location, "Bad character %x (%lc)\n", loc, loc) ;
	current.increment() ;
	}
}

void T_entity_compiler::goto_right_parenthesis(void)
{
for(;;)
	{
	switch (current_item)
		{
		case entity_compiler_item_eof:
			return ;
		case entity_compiler_item_right_parenthesis:
			return ;
		case entity_compiler_item_left_brace:
			next_item() ;
			skip_right_brace() ;
			break ;
		case entity_compiler_item_left_bracket:
			next_item() ;
			skip_right_bracket() ;
			break ;
		case entity_compiler_item_left_parenthesis:
			next_item() ;
			skip_right_parenthesis() ;
			break ;
		default:
			next_item() ;
			break ;
		}
	}
}

void T_entity_compiler::skip_semicolon(void)
{
if (current_item == entity_compiler_item_eof) return ;
next_item() ;
for(;;)
	{
	switch (current_item)
		{
		case entity_compiler_item_eof:
		case entity_compiler_item_right_brace:
			return ;
		case entity_compiler_item_semicolon:
			next_item() ;
			return ;
		case entity_compiler_item_left_brace:
			next_item() ;
			skip_right_brace() ;
			break ;
		case entity_compiler_item_left_bracket:
			next_item() ;
			skip_right_bracket() ;
			break ;
		case entity_compiler_item_left_parenthesis:
			next_item() ;
			skip_right_parenthesis() ;
			break ;
		default:
			next_item() ;
			break ;
		}
	}
}

int T_entity_compiler::skip_colon(void)
{
for(;;)
	{
	switch (current_item)
		{
		case entity_compiler_item_eof:
		case entity_compiler_item_right_brace:
		case entity_compiler_item_right_bracket:
		case entity_compiler_item_right_parenthesis:
			return FALSE ;
		case entity_compiler_item_semicolon:
			next_item() ;
			return FALSE ;
		case entity_compiler_item_colon:
			next_item() ;
			return TRUE ;
		case entity_compiler_item_left_brace:
			next_item() ;
			skip_right_brace() ;
			break ;
		case entity_compiler_item_left_bracket:
			next_item() ;
			skip_right_bracket() ;
			break ;
		case entity_compiler_item_left_parenthesis:
			next_item() ;
			skip_right_parenthesis() ;
			break ;
		default:
			next_item() ;
			break ;
		}
	}
}

int T_entity_compiler::skip_comma(void)
{
for(;;)
	{
	switch (current_item)
		{
		case entity_compiler_item_eof:
		case entity_compiler_item_right_brace:
		case entity_compiler_item_right_bracket:
		case entity_compiler_item_right_parenthesis:
			return FALSE ;
		case entity_compiler_item_semicolon:
			next_item() ;
			return FALSE ;
		case entity_compiler_item_comma:
			next_item() ;
			return TRUE ;
		case entity_compiler_item_left_brace:
			next_item() ;
			skip_right_brace() ;
			break ;
		case entity_compiler_item_left_bracket:
			next_item() ;
			skip_right_bracket() ;
			break ;
		case entity_compiler_item_left_parenthesis:
			next_item() ;
			skip_right_parenthesis() ;
			break ;
		default:
			next_item() ;
			break ;
		}
	}
}

void T_entity_compiler::skip_right_brace(void)
{
for(;;)
	{
	switch (current_item)
		{
		case entity_compiler_item_eof:
			return ;
		case entity_compiler_item_right_brace:
			next_item() ;
			return ;
		case entity_compiler_item_left_brace:
			next_item() ;
			skip_right_brace() ;
			break ;
		case entity_compiler_item_left_bracket:
			next_item() ;
			skip_right_bracket() ;
			break ;
		case entity_compiler_item_left_parenthesis:
			next_item() ;
			skip_right_parenthesis() ;
			break ;
		default:
			next_item() ;
			break ;
		}
	}
}

void T_entity_compiler::skip_right_bracket(void)
{
for(;;)
	{
	switch (current_item)
		{
		case entity_compiler_item_eof:
			return ;
		case entity_compiler_item_right_bracket:
			next_item() ;
			return ;
		case entity_compiler_item_left_brace:
			next_item() ;
			skip_right_brace() ;
			break ;
		case entity_compiler_item_left_bracket:
			next_item() ;
			skip_right_bracket() ;
			break ;
		case entity_compiler_item_left_parenthesis:
			next_item() ;
			skip_right_parenthesis() ;
			break ;
		default:
			next_item() ;
			break ;
		}
	}
}

void T_entity_compiler::skip_right_parenthesis(void)
{
for(;;)
	{
	switch (current_item)
		{
		case entity_compiler_item_eof:
			return ;
		case entity_compiler_item_right_parenthesis:
			next_item() ;
			return ;
		case entity_compiler_item_left_brace:
			next_item() ;
			skip_right_brace() ;
			break ;
		case entity_compiler_item_left_bracket:
			next_item() ;
			skip_right_bracket() ;
			break ;
		case entity_compiler_item_left_parenthesis:
			next_item() ;
			skip_right_parenthesis() ;
			break ;
		default:
			next_item() ;
			break ;
		}
	}
}

void T_entity_compiler::skip_attributes_definition(void)
{
for(;;)
	{
	switch (current_item)
		{
		case entity_compiler_item_eof:
			return ;
		case entity_compiler_item_colon:
			next_item() ;
			return ;
		case entity_compiler_item_semicolon:
			next_item() ;
			return ;
		case entity_compiler_item_left_brace:
			next_item() ;
			skip_right_brace() ;
			break ;
		case entity_compiler_item_left_bracket:
			next_item() ;
			skip_right_bracket() ;
			break ;
		case entity_compiler_item_left_parenthesis:
			next_item() ;
			skip_right_parenthesis() ;
			break ;
		default:
			next_item() ;
			break ;
		}
	}
}

int T_entity_compiler::parse_keyword(const char *keyword)
{
if ((current_item != entity_compiler_item_identifier) || (strcmp(string.string(), keyword) != 0)) return FALSE ;
next_item() ;
return TRUE ;
}

void T_entity_compiler::compile_source_files(void)
{
T_entity_program *program = new T_entity_program ;
T_entity_file *entity_file = files.first ;
while (entity_file != NULL)
	{
	file_name.set(entity_file->file_name) ;
	int fd = open(file_name.string(), O_RDONLY) ;
	if (fd == -1)
		{
		add_error("Can't open file <%s> for reading", file_name.string()) ;
		return ;
		}
	struct stat info ;
	if (fstat(fd, &info) != 0)
		{
		close(fd) ;
		add_error("Can't stat file <%s>", file_name.string()) ;
		return ;
		}
	char *loc = new char[info.st_size + 1] ;
	size_t size_read = read(fd, loc, info.st_size) ;
	close(fd) ;
	if (size_read != (size_t)info.st_size)
		{
		add_error("Can't read file <%s>", file_name.string()) ;
		return ;
		}
	loc[info.st_size] = 0 ;
	entity_file->buffer.set(loc, info.st_size) ;
	current.set(entity_file->buffer) ;
	compile_source(program) ;
	entity_file = entity_file->next ;
	}
//program->dump(stderr) ;
if (errors_count > 0) return ;
program->verify_semantic(this) ;
if (errors_count > 0) return ;
T_string_reference start(files.first->file_name) ;
T_string_reference current(start) ;
T_string_reference last ;
for(;;)
	{
	if (current.current() == 0) break ;
	if (current.current() == '.') last.set(current) ;
	current.increment() ;
	}
if (last.offset > 0)
	{
	T_string base(start, last) ;
	T_string extension(".C") ;
	T_string output_file_name(base, extension) ;
	program->generate(output_file_name) ;
	}
}

void T_entity_compiler::compile_source(T_entity_program *program)
{
next_item() ;
for(;;)
	{
	if (is_eof()) break ;
	T_entity_location where(file_name, location) ;
	if (parse_keyword("class"))
		{
		if (is_identifier())
			{
			T_object_class *object_class = new T_object_class(where) ;
			object_class->name.set(string) ;
			next_item() ;
			if (current_item == entity_compiler_item_left_parenthesis)
				{
				skip_semicolon() ;
				}
			else
				{
				program->object_classes.insert(object_class) ;
				object_class->parse(this, program) ;
				}
			}
		else
			{
			T_object_class *object_class = new T_object_class(where) ;
			program->object_classes.insert(object_class) ;
			object_class->parse(this, program) ;
			}
		}
	else if (parse_keyword("global"))
		{
		T_global *global = new T_global(where, FALSE) ;
		program->globals.insert(global) ;
		global->parse(this) ;
		}
	else if (parse_keyword("module"))
		{
		parse_module(program) ;
		}
	else if (parse_keyword("type"))
		{
		skip_semicolon() ;
		}
	else
		{
		add_error(location, "definition expected.") ;
		skip_semicolon() ;
		}
	}
}

T_type *T_entity_compiler::parse_type(void)
{
T_type *loc = parse_compound_type() ;
if (loc != NULL) return loc ;
if (current_item == entity_compiler_item_identifier)
	{
	T_entity_location where(file_name, location) ;
	T_type_identifier *result = new T_type_identifier(where, string) ;
	next_item() ;
	return result ;
	}
return NULL ;
}

T_type *T_entity_compiler::parse_compound_type(void)
{
T_entity_location where(file_name, location) ;
//if (parse_keyword("boolean")) return new T_type_boolean(where) ;
//if (parse_keyword("character")) return new T_type_character(where) ;
/*if (parse_keyword("string"))
	{
	if (parse_keyword("reference")) return new T_type_string_reference(where) ;
	return new T_type_string(where) ;
	}*/
/*int natural = FALSE ;
if (parse_keyword("natural")) natural = TRUE ;
if (parse_keyword("integer_8")) return new T_type_integer(where, natural, 8) ;
if (parse_keyword("integer_16")) return new T_type_integer(where, natural, 16) ;
if (parse_keyword("integer_32")) return new T_type_integer(where, natural, 32) ;
if (parse_keyword("integer_64")) return new T_type_integer(where, natural, 64) ;
if (natural)
	{
	add_error(location, "integer definition expected.") ;
	return NULL ;
	}
*/
int access = FALSE ;
if (parse_keyword("access")) access = TRUE ;
parse_keyword("direct") ;
parse_keyword("shared") ;
parse_keyword("full") ;
parse_keyword("object") ;
if (parse_keyword("list"))
	{
	if (!parse_keyword("of"))
		{
		add_error(location, "keyword of expected.") ;
		return NULL ;
		}
	T_type *type = parse_type() ;
	if (type == NULL)
		{
		add_error(location, "type expected.") ;
		return NULL ;
		}
	if (parse_keyword("on"))
		{
		if (current_item != entity_compiler_item_identifier)
			{
			add_error("identifier expected.") ;
			delete type ;
			return NULL ;
			}
		T_type_list *type_list = new T_type_list(where, access, type, string) ;
		next_item() ;
		return type_list ;
		}
	T_string string_loc ;
	return new T_type_list(where, access, type, string_loc) ;
	}
if (parse_keyword("reference"))
	{
	if (!parse_keyword("on"))
		{
		add_error(location, "keyword on expected.") ;
		return NULL ;
		}
	T_type *type = parse_type() ;
	if (type == NULL)
		{
		add_error(location, "type expected.") ;
		return NULL ;
		}
	return new T_type_reference(where, access, type) ;
	}
if (access)
	{
	add_error(location, "list or reference definition expected.") ;
	return NULL ;
	}
if (parse_keyword("method"))
	{
	T_type_method *type = new T_type_method(where, FALSE) ;
	type->parse(this) ;
	return type ;
	}
if (parse_keyword("any"))
	{
	parse_keyword("direct") ;
	parse_keyword("shared") ;
	parse_keyword("full") ;
	parse_keyword("object") ;
	if (parse_keyword("vector")) return new T_type_vector(where) ;
	if (parse_keyword("reference")) return new T_type_reference(where, FALSE, NULL) ;
	add_error(location, "keywords vector or reference expected.") ;
	return NULL ;
	}
if (parse_keyword("type")) return new T_type_type(where) ;
/*if (parse_keyword("vector"))
	{
	if (parse_keyword("item")) return new T_type_vector_item(where) ;
	add_error(location, "keyword item expected.") ;
	return NULL ;
	}
*/
return NULL ;
}

T_expression *T_entity_compiler::parse_expression(void)
{
T_entity_location where(file_name, location) ;
if (current_item != entity_compiler_item_pipe_pipe) return parse_test_and_expression() ;
next_item() ;
T_expression_test_or *loc = new T_expression_test_or(where) ;
for(;;)
	{
	T_expression *expression = parse_test_and_expression() ;
	if (expression == NULL)
		{
		add_error(location, "expression expected.") ;
		return loc ;
		}
	loc->expressions.insert(expression) ;
	if (current_item != entity_compiler_item_pipe_pipe) return loc ;
	next_item() ;
	}
}

T_expression *T_entity_compiler::parse_test_and_expression(void)
{
T_entity_location where(file_name, location) ;
T_expression *expression = parse_test_expression() ;
if (expression == NULL) return NULL ;
if (current_item == entity_compiler_item_comma)
	{
	next_item() ;
	T_expression_test_and *loc = new T_expression_test_and(where, expression) ;
	for(;;)
		{
		expression = parse_test_expression() ;
		if (expression == NULL)
			{
			add_error(location, "expression expected.") ;
			return loc ;
			}
		loc->expressions.insert(expression) ;
		if (current_item != entity_compiler_item_comma) return loc ;
		next_item() ;
		}
	}
return expression ;
}

T_expression *T_entity_compiler::parse_test_expression(void)
{
T_entity_location where(file_name, location) ;
if (current_item == entity_compiler_item_question_mark)
	{
	next_item() ;
	T_expression *expression = parse_assign_expression() ;
	if (expression == NULL)
		{
		add_error(location, "expression expected.") ;
		return NULL ;
		}
	return new T_expression_test(where, expression) ;
	}
if (parse_keyword("success")) return new T_expression_success(where) ;
return parse_assign_expression() ;
}

T_expression *T_entity_compiler::parse_assign_expression(void)
{
T_entity_location where(file_name, location) ;
T_expression *expression = parse_logical_or_expression() ;
if (expression == NULL) return NULL ;
if (current_item == entity_compiler_item_equal)
	{
	next_item() ;
	T_expression_assign *loc = new T_expression_assign(where, expression, expression_assign_type_assign) ;
	expression = parse_arithmetic_or_expression() ;
	if (expression == NULL)
		{
		add_error(location, "expression expected.") ;
		return loc ;
		}
	loc->expression = expression ;
	return loc ;
	}
if (current_item == entity_compiler_item_add_equal)
	{
	next_item() ;
	T_expression_assign *loc = new T_expression_assign(where, expression, expression_assign_type_add) ;
	expression = parse_arithmetic_or_expression() ;
	if (expression == NULL)
		{
		add_error(location, "expression expected.") ;
		return loc ;
		}
	loc->expression = expression ;
	return loc ;
	}
return expression ;
}

T_expression *T_entity_compiler::parse_logical_or_expression(void)
{
T_entity_location where(file_name, location) ;
T_expression *expression = parse_logical_and_expression() ;
if (expression == NULL) return NULL ;
if (parse_keyword("or"))
	{
	T_expression_logical_or *loc = new T_expression_logical_or(where, expression) ;
	for(;;)
		{
		expression = parse_logical_and_expression() ;
		if (expression == NULL)
			{
			add_error(location, "expression expected.") ;
			return loc ;
			}
		loc->expressions.insert(expression) ;
		if (!parse_keyword("or")) return loc ;
		}
	}
return expression ;
}

T_expression *T_entity_compiler::parse_logical_and_expression(void)
{
T_entity_location where(file_name, location) ;
T_expression *expression = parse_comparison_expression() ;
if (expression == NULL) return NULL ;
if (parse_keyword("and"))
	{
	T_expression_logical_and *loc = new T_expression_logical_and(where, expression) ;
	for(;;)
		{
		expression = parse_comparison_expression() ;
		if (expression == NULL)
			{
			add_error(location, "expression expected.") ;
			return loc ;
			}
		loc->expressions.insert(expression) ;
		if (!parse_keyword("and")) return loc ;
		}
	}
return expression ;
}

T_expression *T_entity_compiler::parse_comparison_expression(void)
{
T_entity_location where(file_name, location) ;
T_expression *expression = parse_arithmetic_or_expression() ;
if (expression == NULL) return NULL ;
if (current_item == entity_compiler_item_equal_equal)
	{
	next_item() ;
	T_expression_comparison *loc = new T_expression_comparison(where, expression, expression_comparison_type_equal) ;
	expression = parse_arithmetic_or_expression() ;
	if (expression == NULL)
		{
		add_error(location, "expression expected.") ;
		return loc ;
		}
	loc->right = expression ;
	return loc ;
	}
if (current_item == entity_compiler_item_exclamation_mark_equal)
	{
	next_item() ;
	T_expression_comparison *loc = new T_expression_comparison(where, expression, expression_comparison_type_not_equal) ;
	expression = parse_arithmetic_or_expression() ;
	if (expression == NULL)
		{
		add_error(location, "expression expected.") ;
		return loc ;
		}
	loc->right = expression ;
	return loc ;
	}
if (current_item == entity_compiler_item_less)
	{
	next_item() ;
	T_expression_comparison *loc = new T_expression_comparison(where, expression, expression_comparison_type_less) ;
	expression = parse_arithmetic_or_expression() ;
	if (expression == NULL)
		{
		add_error(location, "expression expected.") ;
		return loc ;
		}
	loc->right = expression ;
	return loc ;
	}
if (current_item == entity_compiler_item_less_equal)
	{
	next_item() ;
	T_expression_comparison *loc = new T_expression_comparison(where, expression, expression_comparison_type_less_or_equal) ;
	expression = parse_arithmetic_or_expression() ;
	if (expression == NULL)
		{
		add_error(location, "expression expected.") ;
		return loc ;
		}
	loc->right = expression ;
	return loc ;
	}
if (current_item == entity_compiler_item_greater)
	{
	next_item() ;
	T_expression_comparison *loc = new T_expression_comparison(where, expression, expression_comparison_type_greater) ;
	expression = parse_arithmetic_or_expression() ;
	if (expression == NULL)
		{
		add_error(location, "expression expected.") ;
		return loc ;
		}
	loc->right = expression ;
	return loc ;
	}
if (current_item == entity_compiler_item_greater_equal)
	{
	next_item() ;
	T_expression_comparison *loc = new T_expression_comparison(where, expression, expression_comparison_type_greater_or_equal) ;
	expression = parse_arithmetic_or_expression() ;
	if (expression == NULL)
		{
		add_error(location, "expression expected.") ;
		return loc ;
		}
	loc->right = expression ;
	return loc ;
	}
return expression ;
}

T_expression *T_entity_compiler::parse_arithmetic_or_expression(void)
{
T_entity_location where(file_name, location) ;
T_expression *expression = parse_arithmetic_xor_expression() ;
if (expression == NULL) return NULL ;
if (current_item == entity_compiler_item_pipe)
	{
	next_item() ;
	T_expression_arithmetic_or *loc = new T_expression_arithmetic_or(where, expression) ;
	for(;;)
		{
		expression = parse_arithmetic_xor_expression() ;
		if (expression == NULL)
			{
			add_error(location, "expression expected.") ;
			return loc ;
			}
		loc->expressions.insert(expression) ;
		if (current_item != entity_compiler_item_pipe) return loc ;
		next_item() ;
		}
	}
return expression ;
}

T_expression *T_entity_compiler::parse_arithmetic_xor_expression(void)
{
T_entity_location where(file_name, location) ;
T_expression *expression = parse_arithmetic_and_expression() ;
if (expression == NULL) return NULL ;
if (current_item == entity_compiler_item_circumflex)
	{
	next_item() ;
	T_expression_arithmetic_xor *loc = new T_expression_arithmetic_xor(where, expression) ;
	for(;;)
		{
		expression = parse_arithmetic_and_expression() ;
		if (expression == NULL)
			{
			add_error(location, "expression expected.") ;
			return loc ;
			}
		loc->expressions.insert(expression) ;
		if (current_item != entity_compiler_item_circumflex) return loc ;
		next_item() ;
		}
	}
return expression ;
}

T_expression *T_entity_compiler::parse_arithmetic_and_expression(void)
{
T_entity_location where(file_name, location) ;
T_expression *expression = parse_shift_expression() ;
if (expression == NULL) return NULL ;
if (current_item == entity_compiler_item_ampersand)
	{
	next_item() ;
	T_expression_arithmetic_and *loc = new T_expression_arithmetic_and(where, expression) ;
	for(;;)
		{
		expression = parse_shift_expression() ;
		if (expression == NULL)
			{
			add_error(location, "expression expected.") ;
			return loc ;
			}
		loc->expressions.insert(expression) ;
		if (current_item != entity_compiler_item_ampersand) return loc ;
		next_item() ;
		}
	}
return expression ;
}

T_expression *T_entity_compiler::parse_shift_expression(void)
{
T_entity_location where(file_name, location) ;
T_expression *expression = parse_additive_expression() ;
if (expression == NULL) return NULL ;
if (current_item == entity_compiler_item_less_less)
	{
	next_item() ;
	T_expression_shift_left *loc = new T_expression_shift_left(where, expression) ;
	expression = parse_additive_expression() ;
	if (expression == NULL)
		{
		add_error(location, "expression expected.") ;
		return loc ;
		}
	loc->right = expression ;
	return loc ;
	}
if (current_item == entity_compiler_item_greater_greater)
	{
	next_item() ;
	T_expression_shift_left *loc = new T_expression_shift_left(where, expression) ;
	expression = parse_additive_expression() ;
	if (expression == NULL)
		{
		add_error(location, "expression expected.") ;
		return loc ;
		}
	loc->right = expression ;
	return loc ;
	}
return expression ;
}

T_expression *T_entity_compiler::parse_additive_expression(void)
{
T_entity_location where(file_name, location) ;
T_expression *expression = parse_multiplicative_expression() ;
if (expression == NULL) return NULL ;
T_expression_additive_type type ;
if (current_item == entity_compiler_item_add) type = expression_additive_type_addition ;
else if (current_item == entity_compiler_item_minus) type = expression_additive_type_substraction ;
else return expression ;
next_item() ;
T_expression_additive *loc = new T_expression_additive(where, expression) ;
for(;;)
	{
	expression = parse_multiplicative_expression() ;
	if (expression == NULL)
		{
		add_error(location, "expression expected.") ;
		return loc ;
		}
	loc->items.insert(new T_expression_additive_item(type, expression)) ;
	if (current_item == entity_compiler_item_add) type = expression_additive_type_addition ;
	else if (current_item == entity_compiler_item_minus) type = expression_additive_type_substraction ;
	else return loc ;
	next_item() ;
	}
}

T_expression *T_entity_compiler::parse_multiplicative_expression(void)
{
T_entity_location where(file_name, location) ;
T_expression *expression = parse_left_unary_expression() ;
if (expression == NULL) return NULL ;
T_expression_multiplicative_type type ;
if (current_item == entity_compiler_item_star) type = expression_multiplicative_type_multiplication ;
else if (current_item == entity_compiler_item_slash) type = expression_multiplicative_type_division ;
else if (current_item == entity_compiler_item_percent) type = expression_multiplicative_type_modulus ;
else return expression ;
next_item() ;
T_expression_multiplicative *loc = new T_expression_multiplicative(where, expression) ;
for(;;)
	{
	expression = parse_left_unary_expression() ;
	if (expression == NULL)
		{
		add_error(location, "expression expected.") ;
		return loc ;
		}
	loc->items.insert(new T_expression_multiplicative_item(type, expression)) ;
	if (current_item == entity_compiler_item_star) type = expression_multiplicative_type_multiplication ;
	else if (current_item == entity_compiler_item_slash) type = expression_multiplicative_type_division ;
	else if (current_item == entity_compiler_item_percent) type = expression_multiplicative_type_modulus ;
	else return loc ;
	next_item() ;
	}
}

T_expression *T_entity_compiler::parse_left_unary_expression(void)
{
T_entity_location where(file_name, location) ;
if (parse_keyword("not"))
	{
	T_expression *expression = parse_left_unary_expression() ;
	if (expression == NULL)
		{
		add_error(location, "expression expected.") ;
		return NULL ;
		}
	return new T_expression_logical_not(where, expression) ;
	}
if (current_item == entity_compiler_item_tilde)
	{
	next_item() ;
	T_expression *expression = parse_left_unary_expression() ;
	if (expression == NULL)
		{
		add_error(location, "expression expected.") ;
		return NULL ;
		}
	return new T_expression_bitwise_complement(where, expression) ;
	}
if (current_item == entity_compiler_item_add_add)
	{
	next_item() ;
	T_expression *expression = parse_left_unary_expression() ;
	if (expression == NULL)
		{
		add_error(location, "expression expected.") ;
		return NULL ;
		}
	return new T_expression_pre_increment(where, expression) ;
	}
if (current_item == entity_compiler_item_minus_minus)
	{
	next_item() ;
	T_expression *expression = parse_left_unary_expression() ;
	if (expression == NULL)
		{
		add_error(location, "expression expected.") ;
		return NULL ;
		}
	return new T_expression_pre_decrement(where, expression) ;
	}
if (current_item == entity_compiler_item_add)
	{
	next_item() ;
	T_expression *expression = parse_left_unary_expression() ;
	if (expression == NULL)
		{
		add_error(location, "expression expected.") ;
		return NULL ;
		}
	return new T_expression_plus(where, expression) ;
	}
if (current_item == entity_compiler_item_minus)
	{
	next_item() ;
	T_expression *expression = parse_left_unary_expression() ;
	if (expression == NULL)
		{
		add_error(location, "expression expected.") ;
		return NULL ;
		}
	return new T_expression_minus(where, expression) ;
	}
if (current_item == entity_compiler_item_ampersand)
	{
	next_item() ;
	T_expression *expression = parse_left_unary_expression() ;
	if (expression == NULL)
		{
		add_error(location, "expression expected.") ;
		return NULL ;
		}
	return new T_expression_address(where, expression) ;
	}
return parse_right_unary_expression() ;
}

T_expression *T_entity_compiler::parse_right_unary_expression(void)
{
T_expression *expression = parse_base_expression() ;
if (expression == NULL) return NULL ;
for(;;)
	{
	T_entity_location where(file_name, location) ;
	if (current_item == entity_compiler_item_add_add)
		{
		next_item() ;
		expression = new T_expression_post_increment(where, expression) ;
		}
	else if (current_item == entity_compiler_item_minus_minus)
		{
		next_item() ;
		expression = new T_expression_post_decrement(where, expression) ;
		}
	else
		{
		break ;
		}
	}
for(;;)
	{
	T_entity_location where(file_name, location) ;
	if ((current_item == entity_compiler_item_dot) || (current_item == entity_compiler_item_minus_greater))
		{
		next_item() ;
		if (current_item != entity_compiler_item_identifier)
			{
			add_error(location, "identifier expected.") ;
			return expression ;
			}
		T_entity_location where_identifier(file_name, location) ;
		expression = new T_expression_identifier_access(where_identifier, expression, string, FALSE) ;
		next_item() ;
		}
	else if (current_item == entity_compiler_item_dot_dot)
		{
		next_item() ;
		if (current_item != entity_compiler_item_identifier)
			{
			add_error(location, "identifier expected.") ;
			return expression ;
			}
		T_entity_location where_identifier(file_name, location) ;
		expression = new T_expression_identifier_access(where_identifier, expression, string, TRUE) ;
		next_item() ;
		}
	else if (current_item == entity_compiler_item_left_parenthesis)
		{
		T_entity_location where_access(file_name, location) ;
		next_item() ;
		T_expression_call_access *access = new T_expression_call_access(where_access, expression) ;
		expression = access ;
		if (current_item != entity_compiler_item_right_parenthesis)
			{
			for(;;)
				{
				T_expression *loc = parse_logical_or_expression() ;
				if (loc == NULL)
					{
					add_error(location, "expression expected.") ;
					return expression ;
					}
				access->expressions.insert(loc) ;
				if (current_item == entity_compiler_item_right_parenthesis) break ;
				if (current_item != entity_compiler_item_comma)
					{
					add_error(location, "comma or right parenthesis expected.") ;
					return expression ;
					}
				next_item() ;
				}
			}
		next_item() ;
		}
	else if (current_item == entity_compiler_item_left_bracket)
		{
		T_entity_location where_access(file_name, location) ;
		next_item() ;
		T_expression_array_access *access = new T_expression_array_access(where_access, expression) ;
		expression = access ;
		if (current_item != entity_compiler_item_right_bracket)
			{
			for(;;)
				{
				T_expression *loc = parse_logical_or_expression() ;
				if (loc == NULL)
					{
					add_error(location, "expression expected.") ;
					return expression ;
					}
				access->expressions.insert(loc) ;
				if (current_item == entity_compiler_item_right_bracket) break ;
				if (current_item != entity_compiler_item_comma)
					{
					add_error(location, "comma or right bracket expected.") ;
					return expression ;
					}
				next_item() ;
				}
			}
		next_item() ;
		}
	else
		{
		return expression ;
		}
	}
}

T_expression *T_entity_compiler::parse_base_expression(void)
{
T_entity_location where(file_name, location) ;
if (current_item == entity_compiler_item_integer)
	{
	T_expression_integer *result = new T_expression_integer(where, integer) ;
	next_item() ;
	return result ;
	}
if (current_item == entity_compiler_item_character)
	{
	T_expression_character *result = new T_expression_character(where, character) ;
	next_item() ;
	return result ;
	}
if (current_item == entity_compiler_item_string)
	{
	T_expression_string *result = new T_expression_string(where, string) ;
	next_item() ;
	return result ;
	}
if (parse_keyword("true")) return new T_expression_boolean(where, TRUE) ;
if (parse_keyword("false")) return new T_expression_boolean(where, FALSE) ;
if (parse_keyword("null")) return new T_expression_null(where) ;
if (parse_keyword("var"))
	{
	T_expression_local *result = new T_expression_local(where, FALSE) ;
	result->parse(this) ;
	return result ;
	}
if (parse_keyword("constant"))
	{
	T_expression_local *result = new T_expression_local(where, TRUE) ;
	result->parse(this) ;
	return result ;
	}
if (parse_keyword("if"))
	{
	T_expression_if *result = new T_expression_if(where) ;
	result->parse(this) ;
	return result ;
	}
if (parse_keyword("loop"))
	{
	T_expression_loop *result = new T_expression_loop(where) ;
	result->parse(this) ;
	return result ;
	}
if (parse_keyword("while"))
	{
	T_expression_while *result = new T_expression_while(where) ;
	result->parse(this) ;
	return result ;
	}
if (parse_keyword("leave"))
	{
	T_expression_leave *result = new T_expression_leave(where) ;
	result->parse(this) ;
	return result ;
	}
if (parse_keyword("return"))
	{
	T_expression_return *result = new T_expression_return(where) ;
	result->parse(this) ;
	return result ;
	}
if (parse_keyword("compute"))
	{
	T_expression_compute *result = new T_expression_compute(where) ;
	result->parse(this) ;
	return result ;
	}
if (parse_keyword("case"))
	{
	T_expression_case *result = new T_expression_case(where) ;
	result->parse(this) ;
	return result ;
	}
if (parse_keyword("new"))
	{
	T_expression_new *result = new T_expression_new(where) ;
	result->parse(this) ;
	return result ;
	}
if (current_item == entity_compiler_item_dot_dot_dot)
	{
	T_expression_call_base *result = new T_expression_call_base(where) ;
	next_item() ;
	result->parse(this) ;
	return result ;
	}
	/*
if (parse_keyword("native"))
	{
	if (current_item == entity_compiler_item_left_brace)
		{
		T_expression_native *result = new T_expression_native(where, expression_native_entity) ;
		result->parse(this) ;
		return result ;
		}
	if (parse_keyword("cpp"))
		{
		T_expression_native *result = new T_expression_native(where, expression_native_cpp) ;
		result->parse(this) ;
		return result ;
		}
	add_error(location, "Bad native language.") ;
	return NULL ;
	}
*/
T_type *type = parse_compound_type() ;
if (type != NULL) return new T_expression_type(type->location, type) ;
if (current_item == entity_compiler_item_identifier)
	{
	T_expression_identifier *result = new T_expression_identifier(where, string) ;
	next_item() ;
	return result ;
	}
if (current_item == entity_compiler_item_left_brace)
	{
	T_expression_block *result = new T_expression_block(where) ;
	next_item() ;
	result->parse(this) ;
	return result ;
	}
if (current_item == entity_compiler_item_left_left_bracket)
	{
	T_expression_vector *result = new T_expression_vector(where) ;
	next_item() ;
	result->parse(this) ;
	return result ;
	}
if (current_item == entity_compiler_item_left_parenthesis)
	{
	next_item() ;
	T_expression *loc = parse_expression() ;
	if (loc == NULL)
		{
		add_error(location, "expression expected.") ;
		skip_right_parenthesis() ;
		return NULL ;
		}
	if (!parse_right_parenthesis())
		{
		add_error(location, "right parenthesis expected.") ;
		skip_right_parenthesis() ;
		}
	return loc ;
	}
return NULL ;
}

int T_entity_compiler::can_assign_to(T_type *src, T_type *dst)
{
return TRUE ;
}

// }{--------------------------------------------------------------

void T_entity_compiler::parse_module(T_entity_program *program)
{
if (is_identifier()) next_item() ;
if (current_item != entity_compiler_item_left_brace) return ;
next_item() ;
for(;;)
	{
	if (current_item == entity_compiler_item_right_brace)
		{
		next_item() ;
		return ;
		}
	if (parse_keyword("entry"))
		{
		if (*program->entry_name.string() != 0) add_error(location, "entry already defined.") ;
		if (current_item != entity_compiler_item_colon)
			{
			add_error(location, "colon expected.") ;
			skip_semicolon() ;
			}
		else
			{
			next_item() ;
			if (is_identifier())
				{
				program->entry_name.set(string) ;
				next_item() ;
				if (current_item != entity_compiler_item_semicolon)
					{
					add_error(location, "semicolon expected.") ;
					skip_semicolon() ;
					}
				else
					{
					next_item() ;
					}
				}
			else
				{
				add_error(location, "identifier expected.") ;
				skip_semicolon() ;
				}
			}
		}
	else if (parse_keyword("files"))
		{
		parse_colon() ;
		for(;;)
			{
			if (current_item == entity_compiler_item_semicolon)
				{
				next_item() ;
				break ;
				}
			if (current_item != entity_compiler_item_identifier)
				{
				add_error(location, "file name expected.") ;
				skip_semicolon() ;
				break ;
				}
			add_file(string) ;
			next_item() ;
			if (current_item != entity_compiler_item_comma)
				{
				if (current_item == entity_compiler_item_semicolon)
					{
					next_item() ;
					break ;
					}
				add_error(location, "semicolon or comma expected.") ;
				skip_semicolon() ;
				break ;
				}
			next_item() ;
			}
		}
	else
		{
		add_error(location, "bad module item.") ;
		}
	}
}

// }{--------------------------------------------------------------

T_entity_program::T_entity_program(void)
{
entry = NULL ;
last_index = 0 ;
init_builtins() ;
}

T_object_class *T_entity_program::add_object_class(const T_entity_location &new_location, int new_entity, const T_string new_name, T_object_class *base_class)
{
T_object_class *loc = new T_object_class(new_location, new_name) ;
if (base_class != NULL) loc->base_type = new T_type_identifier(new_location, base_class) ;
object_classes.insert(loc) ;
return loc ;
}

T_object_class *T_entity_program::search_class(const T_string &name)
{
T_object_class *object_class = object_classes.first ;
while (object_class != NULL)
	{
	if (!object_class->complement && (strcmp(object_class->name.string(), name.string()) == 0)) return object_class ;
	object_class = object_class->next ;
	}
return NULL ;
}

T_global *T_entity_program::search_global(const T_string &name)
{
T_global *global = globals.first ;
while (global != NULL)
	{
	if (strcmp(global->name.string(), name.string()) == 0) return global ;
	global = global->next ;
	}
return NULL ;
}

int T_entity_program::is_character(const T_type *type)
{
if ((*character_class->is_good_for_call)(character_class, this, type)) return TRUE ;
return FALSE ;
}

int T_entity_program::is_integer(const T_type *type)
{
if ((*integer_8_class->is_good_for_call)(integer_8_class, this, type)) return TRUE ;
if ((*integer_16_class->is_good_for_call)(integer_16_class, this, type)) return TRUE ;
if ((*integer_32_class->is_good_for_call)(integer_32_class, this, type)) return TRUE ;
if ((*integer_64_class->is_good_for_call)(integer_64_class, this, type)) return TRUE ;
if ((*natural_integer_8_class->is_good_for_call)(natural_integer_8_class, this, type)) return TRUE ;
if ((*natural_integer_16_class->is_good_for_call)(natural_integer_16_class, this, type)) return TRUE ;
if ((*natural_integer_32_class->is_good_for_call)(natural_integer_32_class, this, type)) return TRUE ;
if ((*natural_integer_64_class->is_good_for_call)(natural_integer_64_class, this, type)) return TRUE ;
return FALSE ;
}

int T_entity_program::is_number(const T_type *type)
{
return is_integer(type) ;
}

int T_entity_program::is_increment(const T_type *type)
{
if (is_number(type)) return TRUE ;
if ((*string_reference_class->is_good_for_call)(string_reference_class, this, type)) return TRUE ;
if ((*vector_item_reference_class->is_good_for_call)(vector_item_reference_class, this, type)) return TRUE ;
if (type->is_reference()) return TRUE ;
return FALSE ;
}

void T_entity_program::generate_post_increment(FILE *file, T_expression *expression)
{
if (is_number(expression->type))
	{
	expression->generate(this, file, type_generate_value) ;
	fprintf(file, ".value++") ;
	}
else if ((*string_reference_class->is_good_for_call)(string_reference_class, this, expression->type))
	{
	fprintf(file, "++(") ;
	expression->generate(this, file, type_generate_value) ;
	fprintf(file, ")") ;
	}
else if ((*vector_item_reference_class->is_good_for_call)(vector_item_reference_class, this, expression->type))
	{
	fprintf(file, "++") ;
	expression->generate(this, file, type_generate_value) ;
	}
else if (expression->type->is_reference())
	{
	expression->generate(this, file, type_generate_class_reference) ;
	fprintf(file, " = ((") ;
	((T_type_reference *)expression->type)->type->generate_type_name(file, type_generate_header_reference) ;
	fprintf(file, ")") ;
	expression->generate(this, file, type_generate_class_reference) ;
	fprintf(file, ")[-1]._next") ;
	}
}

void T_entity_program::generate_post_decrement(FILE *file, T_expression *expression)
{
if (is_number(expression->type))
	{
	expression->generate(this, file, type_generate_value) ;
	fprintf(file, ".value--") ;
	}
else if ((*string_reference_class->is_good_for_call)(string_reference_class, this, expression->type))
	{
	fprintf(file, "--(") ;
	expression->generate(this, file, type_generate_value) ;
	fprintf(file, ")") ;
	}
else if ((*vector_item_reference_class->is_good_for_call)(vector_item_reference_class, this, expression->type))
	{
	fprintf(file, "--") ;
	expression->generate(this, file, type_generate_value) ;
	}
}

void integer_32_generate_argv(FILE *file, const T_string &name)
{
fprintf(file, "\t\tif (argc - count < 1) { fprintf(stderr, \"Value expected for argument -%s\\n\") ; errors_count++ ; }\n", name.string()) ;
fprintf(file, "\t\telse { _%s.value = atol(argv[count++]) ; defined_%s++ ; }\n", name.string(), name.string()) ;
}

void string_generate_argv(FILE *file, const T_string &name)
{
fprintf(file, "\t\tif (argc - count < 1) { fprintf(stderr, \"Value expected for argument -%s\\n\") ; errors_count++ ; }\n", name.string()) ;
fprintf(file, "\t\telse { _%s.value.set(argv[count++]) ; defined_%s++ ; }\n", name.string(), name.string()) ;
}

int integer_8_class_is_good_for_call(const T_object_class *object_class, T_entity_program *program, const T_type *call_type)
{
if (call_type->get_class() != class_type_identifier) return FALSE ;
T_object_class *src = ((T_type_identifier *)call_type)->object_class ;
if (src == object_class) return TRUE ;
return FALSE ;
}

int integer_32_class_is_good_for_call(const T_object_class *object_class, T_entity_program *program, const T_type *call_type)
{
if (call_type->get_class() != class_type_identifier) return FALSE ;
T_object_class *src = ((T_type_identifier *)call_type)->object_class ;
if (src == object_class) return TRUE ;
if (src == program->integer_8_class) return TRUE ;
return FALSE ;
}

int integer_64_class_is_good_for_call(const T_object_class *object_class, T_entity_program *program, const T_type *call_type)
{
if (call_type->get_class() != class_type_identifier) return FALSE ;
T_object_class *src = ((T_type_identifier *)call_type)->object_class ;
if (src == object_class) return TRUE ;
if (src == program->integer_8_class) return TRUE ;
if (src == program->integer_32_class) return TRUE ;
return FALSE ;
}

int real_64_class_is_good_for_call(const T_object_class *object_class, T_entity_program *program, const T_type *call_type)
{
if (call_type->get_class() != class_type_identifier) return FALSE ;
T_object_class *src = ((T_type_identifier *)call_type)->object_class ;
if (src == object_class) return TRUE ;
if (src == program->integer_8_class) return TRUE ;
if (src == program->integer_32_class) return TRUE ;
return FALSE ;
}

int string_reference_class_is_good_for_call(const T_object_class *object_class, T_entity_program *program, const T_type *call_type)
{
if (call_type->get_class() != class_type_identifier) return FALSE ;
T_object_class *src = ((T_type_identifier *)call_type)->object_class ;
if (src == object_class) return TRUE ;
if (src == program->string_class) return TRUE ;
return FALSE ;
}

int vector_item_reference_class_is_good_for_call(const T_object_class *object_class, T_entity_program *program, const T_type *call_type)
{
if (call_type->get_class() == class_type_reference) call_type = ((T_type_reference *)call_type)->type ;
if (call_type->get_class() != class_type_identifier) return FALSE ;
T_object_class *src = ((T_type_identifier *)call_type)->object_class ;
if (src == object_class) return TRUE ;
if (src == program->vector_item_class) return TRUE ;
return FALSE ;
}

void T_entity_program::init_builtins(void)
{
T_entity_location location ;
class_class = add_object_class(location, FALSE, "", NULL) ;
boolean_class = add_object_class(location, FALSE, "Boolean", class_class) ;
integer_8_class = add_object_class(location, FALSE, "Integer_8", class_class) ;
integer_16_class = add_object_class(location, FALSE, "Integer_16", class_class) ;
integer_32_class = add_object_class(location, FALSE, "Integer_32", class_class) ;
integer_64_class = add_object_class(location, FALSE, "Integer_64", class_class) ;
natural_integer_8_class = add_object_class(location, FALSE, "Natural_integer_8", class_class) ;
natural_integer_16_class = add_object_class(location, FALSE, "Natural_integer_16", class_class) ;
natural_integer_32_class = add_object_class(location, FALSE, "Natural_integer_32", class_class) ;
natural_integer_64_class = add_object_class(location, FALSE, "Natural_integer_64", class_class) ;
character_class = add_object_class(location, FALSE, "Character", class_class) ;
string_class = add_object_class(location, FALSE, "String", class_class) ;
real_64_class = add_object_class(location, FALSE, "Real_64", class_class) ;
dynamic_string_class = add_object_class(location, FALSE, "Dynamic_string", class_class) ;
string_reference_class = add_object_class(location, FALSE, "String_reference", class_class) ;
list_link_class = add_object_class(location, FALSE, "List_link", class_class) ;
vector_item_class = add_object_class(location, FALSE, "Vector_item", class_class) ;
vector_item_reference_class = add_object_class(location, FALSE, "Vector_item_reference", class_class) ;
vector_class = add_object_class(location, FALSE, "Vector", class_class) ;
type_class = add_object_class(location, FALSE, "Type", class_class) ;
object_class_field_class = add_object_class(location, FALSE, "Object_class_field", class_class) ;
object_class_class = add_object_class(location, FALSE, "Object_class", class_class) ;
{ // boolean
boolean_class->native_cpp_string = "\
int value ;\n\
CLASS_Boolean(void) { value = FALSE ; }\n\
CLASS_Boolean(int new_value) { value = new_value ; }\n\
void operator=(int new_value) { value = new_value ; }\n\
int operator!(void) { return !value ; }\n\
int operator==(int right) const { return value == right ; }\n\
int operator==(CLASS_Boolean right) const { return value == right.value ; }\n\
int operator!=(int right) const { return value != right ; }\n\
int operator!=(CLASS_Boolean right) const { return value != right.value ; }\n" ;
boolean_class->native_cpp_instance_string = "\
INSTANCE_Boolean(void) { data.value = FALSE ; }\n\
INSTANCE_Boolean(int new_value) { data.value = new_value ; }\
void operator=(int new_value) { data.value = new_value ; }\n\
void operator=(CLASS_Boolean new_value) { data.value = new_value.value ; }\n" ;
}
{ // integer_8
integer_8_class->native_cpp_string = "\
T_int_8 value ;\n\
CLASS_Integer_8(void) { value = 0 ; }\n\
CLASS_Integer_8(T_int_8 new_value) { value = new_value ; }\n\
T_int_8 operator-() { return -value ; }\n\
void operator=(T_int_8 new_value) { value = new_value ; }\n\
int operator>=(T_int_8 ref) { return value >= ref ; }\n\
int operator<(T_int_8 ref) { return value < ref ; }\n\
T_int_8 operator/(T_int_8 ref) { return value / ref ; }\n\
T_int_8 operator%(T_int_8 ref) { return value % ref ; }\n" ;
integer_8_class->native_cpp_instance_string = "\
INSTANCE_Integer_8(void) { data.value = 0 ; }\n\
INSTANCE_Integer_8(T_int_8 new_value) { data.value = new_value ; }\n\
INSTANCE_Integer_8(CLASS_Integer_8 new_value) { data.value = new_value.value ; }\n\
void operator=(T_int_8 new_value) { data.value = new_value ; }\n" ;
integer_8_class->is_good_for_call = &integer_8_class_is_good_for_call ;
}
{ // integer_32
integer_32_class->native_cpp_string = "\
T_int_32 value ;\n\
CLASS_Integer_32(void) { value = 0 ; }\n\
CLASS_Integer_32(T_int_32 new_value) { value = new_value ; }\
T_int_32 operator-() { return -value ; }\n\
void operator=(T_int_32 new_value) { value = new_value ; }\n\
int operator==(T_int_32 ref) { return value == ref ; }\n\
int operator==(CLASS_Integer_32 ref) { return value == ref.value ; }\n\
int operator!=(T_int_32 ref) { return value != ref ; }\n\
int operator!=(CLASS_Integer_32 ref) { return value != ref.value ; }\n\
int operator>(T_int_32 ref) { return value > ref ; }\n\
int operator>(CLASS_Integer_32 ref) { return value > ref.value ; }\n\
int operator>=(T_int_32 ref) { return value >= ref ; }\n\
int operator>=(CLASS_Integer_32 ref) { return value >= ref.value ; }\n\
int operator<(T_int_32 ref) { return value < ref ; }\n\
int operator<(CLASS_Integer_32 ref) { return value < ref.value ; }\n\
int operator<=(T_int_32 ref) { return value <= ref ; }\n\
int operator<=(CLASS_Integer_32 ref) { return value <= ref.value ; }\n\
CLASS_Integer_32 operator+(T_int_32 ref) { return CLASS_Integer_32(value + ref) ; }\n\
CLASS_Integer_32 operator+(CLASS_Integer_32 ref) { return CLASS_Integer_32(value + ref.value) ; }\n\
CLASS_Integer_32 operator-(T_int_32 ref) { return CLASS_Integer_32(value - ref) ; }\n\
CLASS_Integer_32 operator-(CLASS_Integer_32 ref) { return CLASS_Integer_32(value - ref.value) ; }\n\
CLASS_Integer_32 operator*(T_int_32 ref) { return CLASS_Integer_32(value * ref) ; }\n\
CLASS_Integer_32 operator*(CLASS_Integer_32 ref) { return CLASS_Integer_32(value * ref.value) ; }\n\
CLASS_Integer_32 operator/(T_int_32 ref) { return CLASS_Integer_32(value / ref) ; }\n\
CLASS_Integer_32 operator/(CLASS_Integer_32 ref) { return CLASS_Integer_32(value / ref.value) ; }\n\
CLASS_Integer_32 operator%(T_int_32 ref) { return CLASS_Integer_32(value % ref) ; }\n\
CLASS_Integer_32 operator%(CLASS_Integer_32 ref) { return CLASS_Integer_32(value % ref.value) ; }\n" ;
integer_32_class->native_cpp_instance_string = "\
INSTANCE_Integer_32(void) { data.value = 0 ; }\n\
INSTANCE_Integer_32(T_int_32 new_value) { data.value = new_value ; }\n\
void operator=(T_int_32 new_value) { data.value = new_value ; }\
void operator=(CLASS_Integer_32 new_value) { data.value = new_value.value ; }\n" ;
integer_32_class->is_good_for_call = &integer_32_class_is_good_for_call ;
integer_32_class->generate_argv = &integer_32_generate_argv ;
}
{ // integer_64
integer_64_class->native_cpp_string = "\
T_int_64 value ;\n\
CLASS_Integer_64(void) { value = 0 ; }\n\
CLASS_Integer_64(T_int_64 new_value) { value = new_value ; }\
T_int_64 operator-() { return -value ; }\n\
void operator=(T_int_64 new_value) { value = new_value ; }\n\
int operator>(T_int_64 ref) { return value > ref ; }\n\
int operator>=(T_int_64 ref) { return value >= ref ; }\n\
int operator<(T_int_64 ref) { return value < ref ; }\n\
int operator<=(T_int_64 ref) { return value <= ref ; }\n\
CLASS_Integer_64 operator+(T_int_64 ref) { return CLASS_Integer_64(value + ref) ; }\n\
CLASS_Integer_64 operator+(CLASS_Integer_32 ref) { return CLASS_Integer_64(value + ref.value) ; }\n\
CLASS_Integer_64 operator-(T_int_64 ref) { return CLASS_Integer_64(value - ref) ; }\n\
CLASS_Integer_64 operator*(T_int_64 ref) { return CLASS_Integer_64(value * ref) ; }\n\
CLASS_Integer_64 operator/(T_int_64 ref) { return CLASS_Integer_64(value / ref) ; }\n\
CLASS_Integer_64 operator%(T_int_64 ref) { return CLASS_Integer_64(value % ref) ; }\n" ;
integer_64_class->native_cpp_instance_string = "\
INSTANCE_Integer_64(void) { data.value = 0 ; }\n\
INSTANCE_Integer_64(T_int_64 new_value) { data.value = new_value ; }\n\
void operator=(T_int_64 new_value) { data.value = new_value ; }\
void operator=(CLASS_Integer_64 new_value) { data.value = new_value.value ; }\n" ;
integer_64_class->is_good_for_call = &integer_64_class_is_good_for_call ;
}
{ // Real_64
real_64_class->native_cpp_string = "\
T_real_64 value ;\n\
CLASS_Real_64(void) { value = 0 ; }\n\
CLASS_Real_64(T_real_64 new_value) { value = new_value ; }\n\
void operator=(T_real_64 new_value) { value = new_value ; }\n\
void operator=(CLASS_Real_64 new_value) { value = new_value.value ; }\n\
void operator=(CLASS_Integer_64 new_value) { value = new_value.value ; }\n\
void operator=(CLASS_String new_value) { value = strtod(new_value.value.content->data, NULL) ; }\n\
int operator<=(T_real_64 new_value) { return value <= new_value ; }\n\
int operator<=(CLASS_Real_64 new_value) { return value <= new_value.value ; }\n\
int operator<(T_real_64 new_value) { return value < new_value ; }\n\
int operator<(CLASS_Real_64 new_value) { return value < new_value.value ; }\n" ;
real_64_class->native_cpp_instance_string = "\
INSTANCE_Real_64(void) { data.value = 0 ; }\n\
INSTANCE_Real_64(T_real_64 new_value) { data.value = new_value ; }\n\
void operator=(T_real_64 new_value) { data.value = new_value ; }\n\
void operator=(CLASS_Real_64 new_value) { data.value = new_value.value ; }\n\
int operator<=(T_real_64 new_value) { return data.value <= new_value ; }\n\
int operator<=(CLASS_Real_64 new_value) { return data.value <= new_value.value ; }\n\
int operator<(T_real_64 new_value) { return data.value < new_value ; }\n\
int operator<(CLASS_Real_64 new_value) { return data.value < new_value.value ; }\n" ;
real_64_class->is_good_for_call = &real_64_class_is_good_for_call ;
}
{ // character
character_class->native_cpp_string = "\
T_character value ;\n\
CLASS_Character(void) { value = 0 ; }\n\
CLASS_Character(T_character new_value) { value = new_value ; }\n\
CLASS_Character operator+(T_int_32 ref) { return CLASS_Character(value + ref) ; }\n\
CLASS_Character operator+(CLASS_Integer_32 ref) { return CLASS_Character(value + ref.value) ; }\n\
CLASS_Character operator+(T_int_64 ref) { return CLASS_Character(value + ref) ; }\n\
CLASS_Character operator+(CLASS_Integer_64 ref) { return CLASS_Character(value + ref.value) ; }\n\
CLASS_Integer_32 operator-(CLASS_Character ref) { return CLASS_Integer_32(value - ref.value) ; }\n\
int operator==(T_character right) const { return value == right ; }\n\
int operator==(CLASS_Character right) const { return value == right.value ; }\n\
int operator!=(T_character right) const { return value != right ; }\n\
int operator!=(CLASS_Character right) const { return value != right.value ; }\n\
int operator<(T_character right) const { return value < right ; }\n\
int operator<(CLASS_Character right) const { return value < right.value ; }\n\
int operator<=(T_character right) const { return value <= right ; }\n\
int operator<=(CLASS_Character right) const { return value <= right.value ; }\n\
int operator>(T_character right) const { return value > right ; }\n\
int operator>(CLASS_Character right) const { return value > right.value ; }\n\
int operator>=(T_character right) const { return value >= right ; }\n\
int operator>=(CLASS_Character right) const { return value >= right.value ; }\n" ;
character_class->native_cpp_instance_string = "\
void operator=(T_character &new_value) { data.value = new_value ; }\
void operator=(CLASS_Character &new_value) { data.value = new_value.value ; }\n" ;
}
{ // string
string_class->native_cpp_string = "\
T_string value ;\n\
CLASS_String(T_string new_value) : value(new_value) {}\n\
void operator=(T_string &new_value) { value.set(new_value) ; }\n\
void operator=(CLASS_String new_value) { value.set(new_value.value) ; }\n\
void operator=(CLASS_Dynamic_string &new_value) ;\n\
T_string &operator+(CLASS_String &new_value) { return value.add(new_value.value) ; }\n\
int operator==(T_string &new_value) { return value.equals(new_value) ; }\n\
int operator==(CLASS_String &new_value) { return value.equals(new_value.value) ; }\n\
int operator!=(T_string &new_value) { return !value.equals(new_value) ; }\n\
int operator!=(CLASS_String &new_value) { return !value.equals(new_value.value) ; }\n\
T_int_32 _size(void) { return (T_int_32)value.content->size ; }\n\
T_int_32 _length(void) { return (T_int_32)value.content->length ; }\n\
CLASS_String(void) {}\n" ;
string_class->native_cpp_string_body = "\
void CLASS_String::operator=(CLASS_Dynamic_string &new_value) { value.set(new_value.value) ; }\n\
" ;
string_class->native_cpp_instance_string = "\
void operator=(T_string &new_value) { data.value.set(new_value) ; }\n\
void operator=(CLASS_String new_value) { data.value.set(new_value.value) ; }\n" ;
string_class->generate_argv = &string_generate_argv ;
}
{ // dynamic_string
dynamic_string_class->native_cpp_string = "\
T_dynamic_string value ;\n\
CLASS_Dynamic_string(void) {}\n\
void operator+=(T_string &new_value) { value.add(new_value) ; }\n\
void operator+=(CLASS_String &new_value) { value.add(new_value.value) ; }\n\
void operator+=(T_character new_value) { value.add(new_value) ; }\n\
void operator+=(CLASS_Character new_value) { value.add(new_value.value) ; }\n" ;
string_reference_class->native_cpp_instance_string = "\n" ;
//string_reference_class->is_good_for_call = &string_reference_class_is_good_for_call ;
}
{ // string_reference
string_reference_class->native_cpp_string = "\
T_string_reference value ;\n\
CLASS_String_reference(void) {}\n\
void operator=(const CLASS_String &ref) { value.set(ref.value) ; _character.value = value.current() ; }\n\
void operator++(void) { value.increment() ; _character.value = value.current() ; }\n\
void operator--(void) { value.decrement() ; _character.value = value.current() ; }\n\
int operator==(T_string_reference &right) const { return value.get_content() == right.get_content() && value.offset == right.offset ; }\n\
int operator==(CLASS_String_reference &right) const { return value.get_content() == right.value.get_content() && value.offset == right.value.offset ; }\n\
CLASS_String_reference operator+(CLASS_Integer_64 new_offset) { CLASS_String_reference loc(*this) ; while (new_offset.value > 0) { new_offset.value-- ; ++loc ; } return loc ; }\n\
void reset(void) { value.reset() ; _character.value = value.current() ; }\n" ;
string_reference_class->native_cpp_instance_string = "\
void operator=(const CLASS_String_reference &ref) { data = ref ; }\n\
void operator=(const CLASS_String &ref) { data = ref ; }\n" ;
string_reference_class->is_good_for_call = &string_reference_class_is_good_for_call ;
T_object_class_field *field = new T_object_class_field(location, FALSE, "character") ;
field->type = new T_type_identifier(location, character_class) ;
string_reference_class->fields.insert(field) ;
}
{ // list_link
list_link_class->native_cpp_string = "\
void *previous ; void *next ;\n\
CLASS_List_link(void) { previous = NULL ; next = NULL ; }\n" ;
}
{ // vector_item
T_object_class_field *field = new T_object_class_field(location, FALSE, "item") ;
field->type = new T_type_reference(location, TRUE, new T_type_identifier(location, class_class)) ;
vector_item_class->fields.insert(field) ;
field = new T_object_class_field(location, FALSE, "previous") ;
field->type = new T_type_reference(location, FALSE, new T_type_identifier(location, vector_item_class)) ;
vector_item_class->fields.insert(field) ;
field = new T_object_class_field(location, FALSE, "next") ;
field->type = new T_type_reference(location, FALSE, new T_type_identifier(location, vector_item_class)) ;
vector_item_class->fields.insert(field) ;
}
{ // vector_item_reference
vector_item_reference_class->native_cpp_string = "\
CLASS_Vector_item_reference(void) { _current_item = NULL ; _item = NULL ; }\n\
void operator=(CLASS_Vector_item *new_current_item) { _current_item = new_current_item ; _item = (_current_item == NULL) ? NULL : _current_item->_item ; }\n\
void operator++(void) { if (_current_item != NULL) { _current_item = _current_item->_next ; _item = (_current_item == NULL) ? NULL : _current_item->_item ; } }\
void operator--(void) { if (_current_item != NULL) { _current_item = _current_item->_previous ; _item = (_current_item == NULL) ? NULL : _current_item->_item ; } }\n" ;
vector_item_reference_class->native_cpp_instance_string = "\
void operator=(CLASS_Vector_item *new_current_item) { data = new_current_item ; }\n" ;
vector_item_reference_class->is_good_for_call = &vector_item_reference_class_is_good_for_call ;
T_object_class_field *field = new T_object_class_field(location, FALSE, "current_item") ;
field->type = new T_type_reference(location, TRUE, new T_type_identifier(location, vector_item_class)) ;
vector_item_reference_class->fields.insert(field) ;
field = new T_object_class_field(location, FALSE, "item") ;
field->type = new T_type_reference(location, FALSE, new T_type_identifier(location, class_class)) ;
vector_item_reference_class->fields.insert(field) ;
}
{ // vector
vector_class->native_cpp_string = "\
CLASS_Vector(void) { _first = NULL ; _last = NULL ; }\n\
void add_item(CLASS_ *new_item) { CLASS_Vector_item *loc = new CLASS_Vector_item ; loc->_item = new_item ; loc->_previous = _last ; loc->_next = NULL ; if (_last == NULL) _first = loc ; else _last->_next = loc ; _last = loc ; }\n" ;
T_object_class_field *field = new T_object_class_field(location, FALSE, "first") ;
field->type = new T_type_reference(location, FALSE, new T_type_identifier(location, vector_item_class)) ;
vector_class->fields.insert(field) ;
field = new T_object_class_field(location, FALSE, "last") ;
field->type = new T_type_reference(location, FALSE, new T_type_identifier(location, vector_item_class)) ;
vector_class->fields.insert(field) ;
}
{ // type
type_class->native_cpp_string = "\
T_type value ;\n\
CLASS_Type(T_type new_value) : value(new_value) {}\n\
CLASS_Type(void) {}\n" ;
}
{ // object_class_field
object_class_field_class->native_cpp_string = "\
CLASS_Object_class_field(T_string new_name, T_type new_type, T_int_32 new_offset) : _name(new_name), _type(new_type), _offset(new_offset) {}\n" ; 
object_class_field_class->native_cpp_instance_string = "\
INSTANCE_Object_class_field(T_string new_name, T_type new_type, T_int_32 new_offset) : data(new_name, new_type, new_offset) {}\n" ;
T_object_class_field *field = new T_object_class_field(location, FALSE, "name") ;
field->type = new T_type_identifier(location, string_class) ;
object_class_field_class->fields.insert(field) ;
field = new T_object_class_field(location, FALSE, "type") ;
field->type = new T_type_identifier(location, type_class) ;
object_class_field_class->fields.insert(field) ;
field = new T_object_class_field(location, FALSE, "offset") ;
field->type = new T_type_identifier(location, integer_32_class) ;
object_class_field_class->fields.insert(field) ;
}
{ // object_class
object_class_class->native_cpp_string = "CLASS_Object_class(const char *new_class_name) : _class_name(new_class_name) {}\n" ;
object_class_class->native_cpp_instance_string = "INSTANCE_Object_class(const char *new_class_name) : data(new_class_name) {}\n" ;
T_object_class_field *field = new T_object_class_field(location, FALSE, "class_name") ;
field->type = new T_type_identifier(location, string_class) ;
object_class_class->fields.insert(field) ;
field = new T_object_class_field(location, FALSE, "size") ;
field->type = new T_type_identifier(location, integer_32_class) ;
object_class_class->fields.insert(field) ;
field = new T_object_class_field(location, FALSE, "data_size") ;
field->type = new T_type_identifier(location, integer_32_class) ;
object_class_class->fields.insert(field) ;
field = new T_object_class_field(location, FALSE, "base_class") ;
field->type = new T_type_reference(location, FALSE, new T_type_identifier(location, object_class_class)) ;
object_class_class->fields.insert(field) ;
field = new T_object_class_field(location, FALSE, "fields") ;
field->type = new T_type_list(location, FALSE, new T_type_identifier(location, object_class_field_class), "link") ;
object_class_class->fields.insert(field) ;
}
}

void T_entity_program::dump(FILE *file) const
{
fprintf(file, "entry : %s ;\n", entry_name.string()) ;
{
T_object_class *object_class = object_classes.first ;
while (object_class != NULL)
	{
	object_class->dump(file) ;
	object_class = object_class->next ;
	}
}
{
T_global *global = globals.first ;
while (global != NULL)
	{
	global->dump(file) ;
	global = global->next ;
	}
}
}

void T_entity_program::verify_semantic(T_entity_compiler *compiler)
{
if (*entry_name.string() == 0)
	{
	compiler->add_error("entry not defined.") ;
	}
else
	{
	entry = search_class(entry_name) ;
	if (entry == NULL) compiler->add_error("class %s not defined for entry.", entry_name.string()) ;
	}
{
T_object_class *object_class = object_classes.first ;
while (object_class != NULL)
	{
	T_object_class *next = object_class->next ;
	if (object_class->complement)
		{
		T_object_class *first_class = search_class(object_class->name) ;
		if (first_class == NULL)
			{
			compiler->add_error(object_class->location, "class %s not defined elsewhere.", object_class->name.string()) ;
			}
		else
			{
			object_classes.remove(object_class) ;
			first_class->complements.insert(object_class) ;
			first_class->use_complement(object_class) ;
			object_class->complement_base = first_class ;
			}
		}
	else
		{
		object_class->complement_base = object_class ;
		}
	object_class = next ;
	}
}
{
T_object_class *object_class = object_classes.first ;
while (object_class != NULL)
	{
	object_class->verify_type_semantic(compiler, this, NULL) ;
	object_class = object_class->next ;
	}
}
{
T_global *global = globals.first ;
while (global != NULL)
	{
	global->verify_semantic(compiler, this, NULL) ;
	global = global->next ;
	}
}
if (compiler->errors_count > 0) return ;
{
T_object_class *object_class = object_classes.first ;
while (object_class != NULL)
	{
	object_class->verify_base_class_semantic(compiler) ;
	object_class = object_class->next ;
	}
}
{
T_object_class *object_class = object_classes.first ;
while (object_class != NULL)
	{
	object_class->verify_semantic(compiler, this, NULL) ;
	object_class = object_class->next ;
	}
}
}

int T_entity_program::generate(const T_string &file_name)
{
fprintf(stderr, "Generate <%s>\n", file_name.string()) ;
FILE *file = fopen(file_name.string(), "w") ;
if (file == NULL)
	{
	fprintf(stderr, "Can't write %s\n", file_name.string()) ;
	return FALSE ;
	}
generate_builtins(file) ;
{
T_object_class *object_class = object_classes.first ;
while (object_class != NULL)
	{
	object_class->generate_names(file) ;
	object_class = object_class->next ;
	}
}
{
T_object_class *object_class = object_classes.first ;
while (object_class != NULL)
	{
	object_class->generate_class(file, this) ;
	object_class = object_class->next ;
	}
}
{
T_object_class *object_class = object_classes.first ;
while (object_class != NULL)
	{
	object_class->generate_instance(file, this) ;
	object_class = object_class->next ;
	}
}
fprintf(file, "CLASS_Vector empty_vector ;\n") ;
fprintf(file, "int test(int value) { return value ; }\n") ;
fprintf(file, "int test(CLASS_Boolean value) { return value.value ; }\n") ;
fprintf(file, "CLASS_Object_class *___duplicate_object(T_duplicate *duplicate_objects, CLASS_Object_class *src)\n") ;
fprintf(file, "{\n") ;
fprintf(file, "T_duplicate_object *loc = duplicate_objects->first ;\n") ;
fprintf(file, "while (loc != NULL)\n") ;
fprintf(file, "\t{\n") ;
fprintf(file, "\tif (loc->old_object == src) return loc->new_object ;\n") ;
fprintf(file, "\tif (loc->new_object == src)\n") ;
fprintf(file, "\t\t{\n") ;
fprintf(file, "\t\tfprintf(stderr, \"loop for %%s %%p\\n\", (((HEADER_ *)src)[-1].introspect)->_class_name.value.string(), src) ;\n") ;
fprintf(file, "\t\t*(char **)0 = 0 ;\n") ;
fprintf(file, "\t\t}\n") ;
fprintf(file, "\tloc = loc->next ;\n") ;
fprintf(file, "\t}\n") ;
fprintf(file, "CLASS_Object_class *class_definition = ((HEADER_ *)src)[-1].introspect ;\n") ;
fprintf(file, "INSTANCE_Object_class *result = (INSTANCE_Object_class *)new char[sizeof(HEADER_) + class_definition->_size.value] ;\n") ;
//fprintf(file, "fprintf(stderr, \"{=> duplicate %%s %%p -> %%p\\n\", class_definition->_class_name.value.string(), src, &result->data) ;\n") ;
fprintf(file, "result->header = ((HEADER_Object_class *)src)[-1] ;\n") ;
//fprintf(file, "fprintf(stderr, \"first=%%p\\n\", duplicate_objects->first) ;\n") ;
fprintf(file, "duplicate_objects->first = new T_duplicate_object(duplicate_objects->first, src, &result->data) ;\n") ;
//fprintf(file, "fprintf(stderr, \"=> first=%%p next=%%p\\n\", duplicate_objects->first, duplicate_objects->first->next) ;\n") ;
fprintf(file, "while (class_definition != NULL)\n") ;
fprintf(file, "\t{\n") ;
fprintf(file, "\tCLASS_Object_class_field *field = class_definition->_fields._first ;\n") ;
fprintf(file, "\twhile (field != NULL)\n") ;
fprintf(file, "\t\t{\n") ;
//fprintf(file, "\t\tfprintf(stderr, \"duplicate field %%s:%%s offset=%%d src=%%p dst=%%p\\n\", class_definition->_class_name.value.string(), field->_name.value.string(), field->_offset.value, src, &result->data) ;\n") ;
fprintf(file, "\t\tfield->_type.value.type->duplicate_field(duplicate_objects, ((const char *)src) + field->_offset.value, ((char *)&result->data) + field->_offset.value) ;\n") ;
fprintf(file, "\t\tfield = ((HEADER_Object_class_field *)field)[-1]._next ;\n") ;
fprintf(file, "\t\t}\n") ;
fprintf(file, "\tclass_definition = class_definition->_base_class ;\n") ;
fprintf(file, "\t}\n") ;
//fprintf(file, "fprintf(stderr, \"}\\n\") ;\n") ;
fprintf(file, "return &result->data ;\n") ;
fprintf(file, "}\n") ;
fprintf(file, "CLASS_Object_class *___duplicate(CLASS_Object_class *src)\n") ;
fprintf(file, "{\n") ;
//fprintf(file, "fprintf(stderr, \"********duplicate %%s %%p\\n\", ((HEADER_ *)src)[-1].introspect->_name.value.string(), src) ;\n") ;
fprintf(file, "T_duplicate duplicate_objects ;\n") ;
fprintf(file, "return ___duplicate_object(&duplicate_objects, src) ;\n") ;
fprintf(file, "}\n") ;
generate_builtins_code(file) ;
{
T_global *global = globals.first ;
while (global != NULL)
	{
	global->generate_declaration(file) ;
	global = global->next ;
	}
}
{
T_object_class *object_class = object_classes.first ;
while (object_class != NULL)
	{
	object_class->generate_definitions(file, this) ;
	object_class = object_class->next ;
	}
}
{
T_global *global = globals.first ;
while (global != NULL)
	{
	global->generate_definition(file) ;
	global = global->next ;
	}
}
fprintf(file, "int main(int argc, const char **argv)\n") ;
fprintf(file, "{\n") ;
fprintf(file, "INSTANCE_%s instance(argc, argv) ;\n", entry->name.string()) ;
fprintf(file, "if (instance.data.errors_count > 0) return 1 ;\n") ;
fprintf(file, "_%s__run(&instance.data) ;\n", entry->name.string()) ;
fprintf(file, "return 0 ;\n") ;
fprintf(file, "}\n") ;
fclose(file) ;
return TRUE ;
}

// }{--------------------------------------------------------------
